/**
    @file        sample_app_mcal_uart_console.c
    @version     1.0.4

    @brief       AUTOSAR - Autosar  Sample Application.
    @details     The standard C library routine printf() over serial , but without all the garbage

    Project      : AUTOSAR 4.0 MCAL
    Platform     : ARM

    Autosar Version       : 4.0.3
    Autosar Revision      : ASR_REL_4_0_REV_0003
    Autosar Conf. Variant :
    Software Version      : 1.0.4
    Build Version         : S32K14X_MCAL_1_0_4_RTM_ASR_REL_4_0_REV_0003_20190307

    (c) Copyright 2019 NXP
    All Rights Reserved.

    This file contains sample code only. It is not part of the production code deliverables.

 */
/*==================================================================================================
==================================================================================================*/

#ifdef __cplusplus
extern "C"{
#endif

/*==================================================================================================
                                         INCLUDE FILES
 1) system and project includes
 2) needed interfaces from external units
 3) internal and external interfaces from this unit
==================================================================================================*/

#include "sample_app_mcal_uart_console.h"
#include "StdRegMacros.h"
#include "Reg_eSys.h"

#include "Mcal.h"
#include "modules.h"
#include <stdio.h>
#include <stdarg.h>

/*==================================================================================================
                                        LOCAL MACROS
==================================================================================================*/

#define LPUART_PORT        1U
/* LPUART IPG Clock in Hz*/
#define LPUART_ASYNCH_CLK           20000000UL
/* LPUART Baudrate */
#define LPUART_BAUDRATE             115200UL
/* LPUART_OSR */
#define LPUART_OSR 3
/* Calculate LINBRR value by the formula */
#define LPUART_SBR              ((LPUART_ASYNCH_CLK / LPUART_BAUDRATE) / (LPUART_OSR+1))

/*==================================================================================================
                                      FILE VERSION CHECKS
==================================================================================================*/


/*==================================================================================================
                          LOCAL TYPEDEFS (STRUCTURES, UNIONS, ENUMS)
==================================================================================================*/

/*==================================================================================================
                                       LOCAL CONSTANTS
==================================================================================================*/
#define TX_BUF_SIZE     512U
#define TX_ON           0x1U
#define TX_OFF          0x0U

extern CONST(uint32, LIN_CONST) LPUART_au32BaseAddrs[];

#if (USE_LIN_MODULE!=STD_ON)
CONST(uint32, LIN_CONST) LPUART_au32BaseAddrs[] =
 {
    #ifdef  LPUART0_BASEADDR
        LPUART0_BASEADDR,
    #endif /* LPUART0_BASEADDR */
    #ifdef  LPUART1_BASEADDR
        LPUART1_BASEADDR,
    #endif /* LPUART1_BASEADDR */
    #ifdef  LPUART2_BASEADDR
        LPUART2_BASEADDR,
    #endif /* LPUART2_BASEADDR */
    #ifdef  LPUART3_BASEADDR
        LPUART3_BASEADDR,
    #endif /* LPUART3_BASEADDR */

};
#endif

/* ========================IPV_LPUART macro definition========================================*/

/**
* @brief        IPV_LPUART macro definition.
* @details      Macro to get base address of LPUART IPs.
*/
/*
* @violates @ref Reg_eSys_LPUART_h_REF_2 Function-like macro defined.
*/
/* @violates @ref Reg_eSys_LPUART_h_REF_9 Within a function-like macro, the arguments shall be enclosed in parentheses. */
/* @violates @ref Reg_eSys_LPUART_h_REF_7 C macros shall only expand to a braced initializer, .. */
#define LPUART_GET_BASE_ADDRESS_U32(offset) ((uint32)( LPUART_au32BaseAddrs[(offset)] ))

/**
* @brief        IPV_LPUART Registers macro definition.
* @details      IPV_LPUART macro to access register LPUART Version ID Register (LPUART_VERID).
*/
/*
* @violates @ref Reg_eSys_LPUART_h_REF_2 Function-like macro defined.
*/
/* @violates @ref Reg_eSys_LPUART_h_REF_1 Re-use of C90 reserved identifier */
#define LPUART_VERID_ADDR32(offset)      ((uint32)((uint32)( LPUART_au32BaseAddrs[(offset)]) + 0x00uL))

/**
* @brief        IPV_LPUART Registers macro definition.
* @details      IPV_LPUART macro to access register LPUART Parameter Register (LPUART_PARAM).
*/
/*
* @violates @ref Reg_eSys_LPUART_h_REF_2 Function-like macro defined.
*/
/* @violates @ref Reg_eSys_LPUART_h_REF_1 Re-use of C90 reserved identifier */
#define LPUART_PARAM_ADDR32(offset)    ((uint32)((uint32)( LPUART_au32BaseAddrs[(offset)]) + 0x04uL ))

/**
* @brief        IPV_LPUART Registers macro definition.
* @details      IPV_LPUART macro to access register LPUART Global Register (LPUART_GLOBAL).
*/
/*
* @violates @ref Reg_eSys_LPUART_h_REF_2 Function-like macro defined.
*/
/* @violates @ref Reg_eSys_LPUART_h_REF_1 Re-use of C90 reserved identifier */
#define LPUART_GLOBAL_ADDR32(offset)    ((uint32)((uint32)( LPUART_au32BaseAddrs[(offset)]) + 0x08uL ))

/**
* @brief        IPV_LPUART Registers macro definition.
* @details      IPV_LPUART macro to access register LPUART Pin Configuration Register (LPUART_PINCFG).
*/
/*
* @violates @ref Reg_eSys_LPUART_h_REF_2 Function-like macro defined.
*/
/* @violates @ref Reg_eSys_LPUART_h_REF_1 Re-use of C90 reserved identifier */
#define LPUART_PINCFG_ADDR32(offset)    ((uint32)((uint32)( LPUART_au32BaseAddrs[(offset)]) + 0x0CuL ))

/**
* @brief        IPV_LPUART Registers macro definition.
* @details      IPV_LPUART macro to access register LPUART Baud Rate Register (LPUART_BAUD).
*/
/*
* @violates @ref Reg_eSys_LPUART_h_REF_2 Function-like macro defined.
*/
/* @violates @ref Reg_eSys_LPUART_h_REF_1 Re-use of C90 reserved identifier */
#define LPUART_BAUD_ADDR32(offset)    ((uint32)((uint32)( LPUART_au32BaseAddrs[(offset)]) + 0x10uL ))

/**
* @brief        IPV_LPUART Registers macro definition.
* @details      IPV_LPUART macro to access register LPUART Status Register (LPUART_STAT).
*/
/*
* @violates @ref Reg_eSys_LPUART_h_REF_2 Function-like macro defined.
*/
/* @violates @ref Reg_eSys_LPUART_h_REF_1 Re-use of C90 reserved identifier */
#define LPUART_STAT_ADDR32(offset)    ((uint32)((uint32)( LPUART_au32BaseAddrs[(offset)]) + 0x14uL ))

/**
* @brief        IPV_LPUART Registers macro definition.
* @details      IPV_LPUART macro to access register LPUART Control Register (LPUART_CTRL).
*/
/*
* @violates @ref Reg_eSys_LPUART_h_REF_2 Function-like macro defined.
*/
/* @violates @ref Reg_eSys_LPUART_h_REF_1 Re-use of C90 reserved identifier */
#define LPUART_CTRL_ADDR32(offset)    ((uint32)((uint32)( LPUART_au32BaseAddrs[(offset)]) + 0x18uL ))

/**
* @brief        IPV_LPUART Registers macro definition.
* @details      IPV_LPUART macro to access register LPUART Data Register (LPUART_DATA).
*/
/*
* @violates @ref Reg_eSys_LPUART_h_REF_2 Function-like macro defined.
*/
/* @violates @ref Reg_eSys_LPUART_h_REF_1 Re-use of C90 reserved identifier */
#define LPUART_DATA_ADDR32(offset)    ((uint32)((uint32)( LPUART_au32BaseAddrs[(offset)]) + 0x1CuL ))

/**
* @brief        IPV_LPUART Registers macro definition.
* @details      IPV_LPUART macro to access register LPUART Match Address Register (LPUART_MATCH).
*/
/*
* @violates @ref Reg_eSys_LPUART_h_REF_2 Function-like macro defined.
*/
/* @violates @ref Reg_eSys_LPUART_h_REF_1 Re-use of C90 reserved identifier */
#define LPUART_MATCH_ADDR32(offset)    ((uint32)((uint32)( LPUART_au32BaseAddrs[(offset)]) + 0x20uL ))

/**
* @brief        IPV_LPUART Registers macro definition.
* @details      IPV_LPUART macro to access register LPUART Modem IrDA Register (LPUART_MODIR).
*/
/*
* @violates @ref Reg_eSys_LPUART_h_REF_2 Function-like macro defined.
*/
/* @violates @ref Reg_eSys_LPUART_h_REF_1 Re-use of C90 reserved identifier */
#define LPUART_MODIR_ADDR32(offset)    ((uint32)((uint32)( LPUART_au32BaseAddrs[(offset)]) + 0x24uL ))

/**
* @brief        IPV_LPUART Registers bits - Control Register  bit masks.
* @details      Receiver Enable bit mask.
*/
/* @violates @ref Reg_eSys_LPUART_h_REF_1 Re-use of C90 reserved identifier */
#define LPUART_CTRL_RE_MASK_U32                 ((uint32)0x00040000U)

/**
* @brief        IPV_LPUART Registers bits - Control Register  bit masks.
* @details      Transmitter Enable bit mask.
*/
/* @violates @ref Reg_eSys_LPUART_h_REF_1 Re-use of C90 reserved identifier */
#define LPUART_CTRL_TE_MASK_U32                 ((uint32)0x00080000U)

/**
* @brief        IPV_LPUART Registers bits - Control Register  bit masks.
* @details      Idle Line Interrupt Enable bit mask.
*/
/* @violates @ref Reg_eSys_LPUART_h_REF_1 Re-use of C90 reserved identifier */
#define LPUART_CTRL_ILIE_MASK_U32               ((uint32)0x00100000U)

/**
* @brief        IPV_LPUART Registers bits - Control Register  bit masks.
* @details      Receiver Full Interrupt Enable bit mask.
*/
/* @violates @ref Reg_eSys_LPUART_h_REF_1 Re-use of C90 reserved identifier */
#define LPUART_CTRL_RIE_MASK_U32                ((uint32)0x00200000U)

/**
* @brief        IPV_LPUART Registers bits - Control Register  bit masks.
* @details      Transmission Complete Interrupt Enable bit mask.
*/
/* @violates @ref Reg_eSys_LPUART_h_REF_1 Re-use of C90 reserved identifier */
#define LPUART_CTRL_TCIE_MASK_U32               ((uint32)0x00400000U)

/**
* @brief        IPV_LPUART Registers bits - Control Register  bit masks.
* @details      Transmitter Interrupt Enable bit mask.
*/
/* @violates @ref Reg_eSys_LPUART_h_REF_1 Re-use of C90 reserved identifier */
#define LPUART_CTRL_TIE_MASK_U32                ((uint32)0x00800000U)



/* STAT mask*/
/**
* @brief        IPV_LPUART Registers bits - Status Register  bit masks.
* @details      Receive Data Register Full Flag bit mask.
*/
/* @violates @ref Reg_eSys_LPUART_h_REF_1 Re-use of C90 reserved identifier */
#define LPUART_STAT_RDRF_MASK_U32               ((uint32)0x00200000U)
/**
* @brief        IPV_LPUART Registers bits - Status Register  bit masks.
* @details      Transmit Data Register Empty Flag bit mask.
*/
/* @violates @ref Reg_eSys_LPUART_h_REF_1 Re-use of C90 reserved identifier */
#define LPUART_STAT_TDRE_MASK_U32               ((uint32)0x00800000U)

/* DATA mask */
/**
* @brief        IPV_LPUART Registers bits - Data Register  bit masks.
* @details      Read / Transmit 8 bit data bit mask.
*/
/* @violates @ref Reg_eSys_LPUART_h_REF_1 Re-use of C90 reserved identifier */
#define LPUART_DATA_DATA8_MASK_U32               ((uint32)0x000000FFU)

/*==================================================================================================
                                       LOCAL VARIABLES
==================================================================================================*/


/*==================================================================================================
                                       GLOBAL CONSTANTS
==================================================================================================*/
/*==================================================================================================
                                       GLOBAL VARIABLES
==================================================================================================*/
/**
@brief This is the TX buffer used as a FIFO
*/
static char SampleApp_UART_Tx_Buf[TX_BUF_SIZE] = {0};

/**
@brief SampleApp_TxHead index points to the location from the SampleApp_UART_Tx_Buf for the next char to send
*/
static volatile uint16_t    SampleApp_TxHead = 0U;
/**
@brief SampleApp_TxTail index points to the location from the SampleApp_UART_Tx_Buf for the next char to put in the buffer
*/
static volatile uint16_t    SampleApp_TxTail = 0U;
/**
@brief Represents the state of the UART. TX_ON if the uart is busy, TX_OFF if the UART is idle
*/
static volatile uint8_t     SampleApp_TxState = TX_OFF;

/*==================================================================================================
                                   LOCAL FUNCTION PROTOTYPES
==================================================================================================*/

static void SampleApp_Uart_Str(const char * buf, unsigned int len);

static uint32 SampleApp_Uart_Itoa(uint32 num, char* str, int base);

int SampleApp_Printf (char *text, uint32 value);

static char* SampleApp_Uart_ReverseString(char *string, unsigned int length) ;

static uint32 SampleApp_Uart_StringLength(char *pointer);
/*==================================================================================================
                                       LOCAL FUNCTIONS
==================================================================================================*/

/*Get String lenght*/

static uint32 SampleApp_Uart_StringLength(char *pointer)
{
   uint32 c = 0;
 
   while( *(pointer + c) != '\0' )
      c++;
 
   return c;
}


/*Revrse a String given as parameter*/

static char* SampleApp_Uart_ReverseString(char *string, unsigned int length) 
{
   int c=0; 

   char *begin, *end, temp;
 
   begin  = string;
   end    = string;
 
   for (c = 0; c < length - 1; c++)
      end++;
 
   for (c = 0; c < length/2; c++)
   {        
      temp   = *end;
      *end   = *begin;
      *begin = temp;
 
      begin++;
      end--;
   }
   return string;
}

/*Integer to string conversion return the lenght of the result string*/
static uint32 SampleApp_Uart_Itoa(uint32 num, char* str, int base)
{
    int idx = 0;

    /* Handle 0 explicitely, otherwise empty string is printed for 0 */
    if (num == 0)
    {
        str[idx++] = '0';
        str[idx] = '\0';
    }
	else
	{
		/* Process individual digits*/
		while (num != 0)
    {
        int rem = num % base;
        str[idx++] = (rem > 9)? (rem-10) + 'a' : rem + '0';
        num = num/base;
    }
		str[idx] = '\0';

    /*Reverse the string*/
    SampleApp_Uart_ReverseString(str, idx);
	}
    return idx;
}

/**
@brief   Send a character buffer to the UART console
@details

@return None
@retval None

@pre None
@post None
*/
static void SampleApp_Uart_Str(const char * buf, unsigned int len)
{
    unsigned int i = 0;
    
    while (i != len)
    {
        SampleApp_PutChar(buf[i]);
        i++;
    }
}

/*==================================================================================================
                                       GLOBAL FUNCTIONS
==================================================================================================*/
ISR(LPUART_Isr_UART_TX);


/**
@brief   Print a formated string to the UART, add a CR to the end o the string
@details

@return number of characters printed
@retval None

@pre None
@post None
*/
int SampleApp_Printf (char *text, uint32 value)
{
    static char input_string[256];
	uint32 len_text=0;
	uint32 len_strconv=0;
    uint32 len=0;
	
	int idx=0;
	
	len_text=SampleApp_Uart_StringLength(text);
	
	/*text lenght should be totoal string lenght (255) - lenght of max Uint32 value converted to char(10)*/
	if(len_text >= (255 - 10))
	{
		return 0;
	}
	/*Get the input text local to input_string*/
	for(idx=0; idx<len_text; idx++)
	{
		input_string[idx]=text[idx];
	}
    /*Itoa*/
	len_strconv= SampleApp_Uart_Itoa(value, &input_string[idx], 10);
	/*Total lenght of the string to be printed in console*/
	len=len_text+len_strconv;
	
	/* Send the buffer to uart*/
    SampleApp_Uart_Str (input_string, (uint32)len);
    /*send CR char*/
    SampleApp_PutChar('\r');
    return len;
}

/*================================================================================================*/
/**
@brief   Setup LINFlex for SCI/UART mode for 115200 bps
@details

@return None
@retval None

@pre None
@post None
*/
/*================================================================================================*/
void SampleApp_UART_ConsoleInit(void)
{

    SampleApp_TxState = TX_OFF;
    /* prepare for INIT mode */
    REG_WRITE32(LPUART_CTRL_ADDR32(LPUART_PORT), 0x0UL);
    /* write Baudrate registers */
    REG_WRITE32(LPUART_BAUD_ADDR32(LPUART_PORT), (LPUART_OSR << 24) | LPUART_SBR );

    /* transmit enable */
    
    /* Enable Rx interrupt */
    /*REG_BIT_SET32(LPUART_CTRL_ADDR32(LPUART_PORT), LPUART_CTRL_RE_MASK_U32 );*/
}

/*================================================================================================*/
/**
@brief   Wait until a character is received on UART and return it
@details

@return The Received char
@retval None

@pre None
@post None
*/
/*================================================================================================*/
char SampleApp_GetChar (void)
{
    char new_char;
    uint32_t temp_reg ;


    temp_reg = LPUART_STAT_RDRF_MASK_U32;
    /* Wait until character has been received */
    /* RMB=1 - buffer ready to be read by software w1c */
    while ( temp_reg != (temp_reg & REG_READ32(LPUART_STAT_ADDR32(LPUART_PORT))) )
    {
        /* wait for a char */
    };

    /* char is present: read it and reset the flags */
    new_char = (char) (REG_READ32(LPUART_DATA_ADDR32(LPUART_PORT)) & LPUART_DATA_DATA8_MASK_U32);

    return new_char;
}


/*================================================================================================*/
/**
@brief   Send a character on UART. If the tx is busy transmitting then put in the buffer.
@details

@return None
@retval None

@pre None
@post None
*/
/*================================================================================================*/
void SampleApp_PutChar (char ch)
{

    /*check if uart is  busy */
    if (TX_ON == SampleApp_TxState)
    {
        /* Disable interrupts*/
        SuspendAllInterrupts();
        /* Put a character in the circular buffer */
        /* save the char in to the buffer*/
        SampleApp_UART_Tx_Buf[SampleApp_TxTail] = ch;
        /* increment the index */

        SampleApp_TxTail++;

	        /* check the tail index from the buffer */
        if (TX_BUF_SIZE < SampleApp_TxHead)
        {            
			while(1);
        }			
		
        /* check the tail index from the buffer */
        if (TX_BUF_SIZE <= SampleApp_TxTail)
        {        

			/* adjust if necessary  for overflow*/
            if (0 == SampleApp_TxHead)
            {
                SampleApp_TxTail = TX_BUF_SIZE - 1;
            }
            else
            {
                SampleApp_TxTail = 0;
            }
        }
        else
        {
            /* buffer full */
            if (SampleApp_TxHead == SampleApp_TxTail)
            {
                SampleApp_TxTail--;
            }
        }
        /* Enable interrupts */
        ResumeAllInterrupts();
    }
    else
    {
        /* Send the character */
        SampleApp_TxState = TX_ON;
        REG_WRITE32(LPUART_DATA_ADDR32(LPUART_PORT), (uint32_t)ch);
        /* Enable Tx interrupt */
        REG_BIT_SET32(LPUART_CTRL_ADDR32(LPUART_PORT), LPUART_CTRL_TE_MASK_U32 | LPUART_CTRL_TIE_MASK_U32);

    }

}

/*================================================================================================*/
/**
@brief   Check if a char was received in the receive buffer.
@details

@return  - 1 if the char is present in UART buffer and 0 if none
@retval None

@pre None
@post None
*/
/*================================================================================================*/
int SampleApp_GetChar_present (void)
{
    return (0x0U != (LPUART_STAT_RDRF_MASK_U32 & REG_READ32(LPUART_STAT_ADDR32(LPUART_PORT))));
}

/*================================================================================================*/
/**
@brief   UART Tx ISR Process function.
@details

@return None
@retval None

@pre None
@post None
*/
/*================================================================================================*/
ISR(LPUART_Isr_UART_TX)
{
/*    uint32_t reg_temp;*/

    volatile uint32_t temp_reg;


    temp_reg = REG_READ32(LPUART_STAT_ADDR32(LPUART_PORT));
    
    if ( LPUART_STAT_TDRE_MASK_U32 == (LPUART_STAT_TDRE_MASK_U32 & temp_reg) )
    {
        /*clear interrupt flag*/
        /* w1c */
        /*  REG_WRITE32(reg_temp, val_temp);*/
        /*  REG_WRITE32(reg_temp, LPUART_UARTSR_DTF_MASK_U32);*/

        /* Disable interrupts*/
       /* SuspendAllInterrupts();*/

        /* check for more chars to send */
        if (0x0U == (SampleApp_TxTail - SampleApp_TxHead))
        {
            SampleApp_TxState = TX_OFF;
            SampleApp_TxHead = 0x0U;
            SampleApp_TxTail = 0x0U;
            /* Disable the Tx interrupt */
            REG_BIT_CLEAR32(LPUART_CTRL_ADDR32(LPUART_PORT), LPUART_CTRL_TIE_MASK_U32);
            
            /*enable RX interrupts*/
           /*  REG_BIT_SET32(LPUART_CTRL_ADDR32(LPUART_PORT), LPUART_CTRL_RIE_MASK_U32);*/
        }
        else
        {
            /* adjust the head index if necessary */
            if (TX_BUF_SIZE <= SampleApp_TxHead)
            {
                SampleApp_TxHead = 0x0U;
            }
            /* send the next char from buffer */
            REG_WRITE32(LPUART_DATA_ADDR32(LPUART_PORT), (uint32_t)SampleApp_UART_Tx_Buf[SampleApp_TxHead]);
            /* increment the index*/
            SampleApp_TxHead++;
           
        }
        /* Enable interrupts */
        /*ResumeAllInterrupts();*/

    }
    EXIT_INTERRUPT();
}
/*================================================================================================*/


/*================================================================================================*/
/**
@brief   Wait for the uart to send.
@details

@return None
@retval None

@pre None
@post None
*/
/*================================================================================================*/
void SampleApp_WaitTx(void)
{
    while(TX_OFF != SampleApp_TxState)
    {
        /* wait */
    }
}

/*================================================================================================*/
#ifdef __cplusplus
}
#endif
